#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# id.py
#

#
# This program is free software; you can redistribute it and/or modify  
# it under the terms of the GNU General Public License as published by  
# the Free Software Foundation; either version 2 of the License, or     
# (at your option) any later version.                                   
#                                                                         
# A copy of the license can be found in the license.txt file supplied   
# with this software or at: http://www.gnu.org/copyleft/gpl.html       
#


class   ID(object) :
    '''
    Identifier for nodes and user-defined objects. New instances of this class
    are created either when a node joins the network, or by the local node
    inserting a user-defined object.

    Once created, an ID instance is unmodifiable.
    '''

    def __init__(self, id) :
        self._id = id
        ## __init__()

    def __str__(self) :
        return '<ID %s>' % (str(self._id),)
        ## __str__()

    def __lt__(self, rhs) :
        if not isinstance(rhs, self.__class__) :
            raise TypeError

        return self.id < rhs.id
        ## __lt__()

    def __gt__(self, rhs) :
        if not isinstance(rhs, self.__class__) :
            raise TypeError

        return self.id > rhs.id
        ## __gt__()

    def __eq__(self, rhs) :
        if not isinstance(rhs, self.__class__) :
            raise TypeError

        return self.id == rhs.id
        ## __eq__()

    def __ne__(self, rhs) :
        return  not self.__eq__(rhs)
        ## __ne__()

    def __cmp__(self, rhs) :
        if not isinstance(rhs, self.__class__) :
            raise TypeError

        if self.id < rhs.id :
            return -1
        elif self.id > rhs.id :
            return 1
        return rhs.id == self.id
        ## __cmp__()

    def getID(self) :
        return self._id
        ## getID()
    id = property(getID)

    def isInInterval(self, fromID, toID) :
        '''
        Checks if this ID is in the interval determined by the two given IDs.
        Neither of the boundary IDs is included in the interval. If both IDs
        match, the interval is assumed to span the whole ID ring.

        @param fromID
                   Lower bound of interval.
        @param toID
                   Upper bound of interval.
        @return If this key is included in the given interval.
        '''
        # both interval bounds are equal -> calculate out of equals
        if fromID == toID :
            # every ID is contained in the interval except of the two bounds
            return self.__ne__(fromID)

        # interval does not cross zero -> compare with both bounds
        if fromID < toID :
            return self.__gt__(fromID) and self.__lt__(toID)
            
        # interval crosses zero -> split interval at zero
        # calculate min and max IDs
        return self.__gt__(fromID) or self.__lt__(toID)
        ## isInInterval()

    ## class ID

